package com.mrzhou.core.tool.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.mrzhou.core.tool.api.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Map;

/**
 * SpringBoot的RestTemplate工具类
 */
@Slf4j
public class RestTemplateUtil {

    private static RestTemplate restTemplate = SpringUtil.getBean(RestTemplate.class);

    public static <T> R<T> requestJson(RestTemplate restTemplate, String url, Object uriVariables, Class<T> responseType, HttpHeaders headers) {
        return requestJson(restTemplate, url, uriVariables, responseType, headers, null);
    }

    /**
     * 将获取的参数统一封装到R
     */
    public static <T> R<T> requestJson(RestTemplate restTemplate, String url, Object uriVariables, Class<T> responseType, HttpHeaders headers, HttpMethod method) {
        if(method == null) {
            method = HttpMethod.POST;
        }
        if (headers == null) {
            headers = new HttpHeaders();
        }
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        HttpEntity<Object> httpEntity = null;
        ResponseEntity<T> resp = null;

        if(method.compareTo(HttpMethod.GET) == 0) {
            httpEntity = new HttpEntity<>(null, headers);
            StringBuffer sb = new StringBuffer(url + "?");
            if(uriVariables instanceof Map) {
                if(null == uriVariables) {
                    resp = restTemplate.exchange(url, HttpMethod.GET, httpEntity, responseType);
                } else {
                    Map<String, String> param = (Map<String, String>) uriVariables;
                    for (Map.Entry<String, ?> entry : param.entrySet()) {
                        sb.append(entry.getKey()).append("=").append("{").append(entry.getKey()).append("}");
                    }
                    resp = restTemplate.exchange(sb.toString(), HttpMethod.GET, httpEntity, responseType, param);
                }
            }
        } else {
            httpEntity = new HttpEntity<>(uriVariables, headers);
            resp = restTemplate.exchange(url, method, httpEntity, responseType);
        }

        log.info("调用restTemplate的post！请求url[ {} ], 参数[ {} ], 返回值[ {} ]", url, JacksonUtil.toJsonString(uriVariables), JacksonUtil.toJsonString(resp.getBody()));
        return R.data(resp.getStatusCode().value(), resp.getBody(), "");
    }


    /**
     * 发送JSON请求
     */
    public static <T> T requestJson(RestTemplate restTemplate, String url, Object uriVariables, ParameterizedTypeReference<T> responseType) {
        return requestJson(restTemplate, url, uriVariables, responseType, null);
    }

    public static <T> T requestJson(RestTemplate restTemplate, String url, Object uriVariables, ParameterizedTypeReference<T> responseType, HttpHeaders headers) {
        if (headers == null) {
            headers = new HttpHeaders();
        }
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        HttpEntity<Object> httpEntity = new HttpEntity<>(uriVariables, headers);
        ResponseEntity<T> resp = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);

        log.info("调用restTemplate的post！请求url[ {} ], 参数[ {} ], 返回值[ {} ]", url, uriVariables, JacksonUtil.toJsonString(resp.getBody()));
        return resp.getBody();

    }

    public static <T> T requestPost(RestTemplate restTemplate, String url, Map<String, ?> uriVariables, TypeReference<T> responseType) {
        return requestPost(restTemplate, url, uriVariables, responseType, null);
    }

    public static <T> T requestPost(RestTemplate restTemplate, String url, Map<String, ?> uriVariables, TypeReference<T> responseType, HttpHeaders headers) {
        T temp = null;
        if(headers == null) {
            headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        }

        // 封装参数
        MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
        for (Map.Entry<String, ?> entry : uriVariables.entrySet()) {
            param.add(entry.getKey(), entry.getValue());
        }

        ParameterizedTypeReference<String> type = new ParameterizedTypeReference<String>() {
        };

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(param, headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, type);
        HttpStatus status = responseEntity.getStatusCode();
        if (status.value() == 200) {
            temp = JacksonUtil.parseObject(responseEntity.getBody(), responseType);
        }

        log.info("调用restTemplate的post！请求url[ {} ], 参数[ {} ], 返回值[ {} ]", url, JacksonUtil.toJsonString(param), JacksonUtil.toJsonString(temp));

        return temp;
    }

    public static <T> T requestGet(RestTemplate restTemplate, String url, Map<String, ?> param, TypeReference<T> responseType, HttpHeaders headers) {
        if(null == headers) {
            headers = new HttpHeaders();
        }
        HttpEntity<String> requestEntity = new HttpEntity<>(null, headers);
        String result;
        if (null == param || param.size() <= 0) {
            result = restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class).getBody();
        } else {
            StringBuffer sb = new StringBuffer(url + "?");
            for (Map.Entry<String, ?> entry : param.entrySet()) {
                sb.append(entry.getKey()).append("=").append("{").append(entry.getKey()).append("}");
            }
            ResponseEntity<String> body = restTemplate.exchange(sb.toString(), HttpMethod.GET, requestEntity, String.class, param);
            result = body.getBody();
        }
        log.info("调用restTemplate的post！请求url[ {} ], 参数[ {} ], 返回值[ {} ]", url, JacksonUtil.toJsonString(param), result);
        return JacksonUtil.parseObject(result, responseType);
    }

    public static <T> T requestGet(RestTemplate restTemplate, String url, Map<String, ?> param, TypeReference<T> responseType) {
        return requestGet(restTemplate, url, param, responseType, null);
    }

    public static <T> T requestMultipartFile(RestTemplate restTemplate, String url, Map<String, ?> param, String fileKey, MultipartFile file, TypeReference<T> responseType) throws IOException {
        Resource resource = new ByteArrayResource(file.getBytes());
        return requestFile(restTemplate, url, param, fileKey, file.getOriginalFilename(), resource, responseType);
    }

    public static <T> T requestFile(RestTemplate restTemplate, String url, Map<String, ?> param, String fileKey, String fileName, String fileURL, TypeReference<T> responseType) throws Exception {
        URL filePath = new URL(fileURL);
        Resource resource = new UrlResource(filePath);
        return requestFile(restTemplate, url, param, fileKey, fileName, resource, responseType);
    }

    public static <T> T requestFile(RestTemplate restTemplate, String url, Map<String, ?> param, String fileKey, File file, TypeReference<T> responseType) {
        Resource resource = new FileSystemResource(file);
        return requestFile(restTemplate, url, param, fileKey, file.getName(), resource, responseType);
    }

    public static <T> T requestFile(RestTemplate restTemplate, String url, Map<String, ?> param, String fileKey, String fileName, Resource resource, TypeReference<T> responseType) {
        MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpHeaders fileHeader = new HttpHeaders();
        fileHeader.setContentType(MediaType.MULTIPART_FORM_DATA);
        fileHeader.setContentDispositionFormData("uploadFile", fileName);

        HttpEntity<Resource> fileEntity = new HttpEntity<>(resource, fileHeader);
        multiValueMap.add(fileKey, fileEntity);
        for (Map.Entry<String, ?> entry : param.entrySet()) {
            multiValueMap.add(entry.getKey(), entry.getValue());
        }

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, headers);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
        return JacksonUtil.parseObject(responseEntity.getBody(), responseType);
    }

/*

    public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse response) throws IOException {
                return true;
            }
            @Override
            public void handleError(ClientHttpResponse response) throws IOException {

            }
        });
        Map<String, String> param = new HashMap<>();
        param.put("id", "1123598821738675201");
        TypeReference<Map> reference = new TypeReference<Map>(){};
        HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic c2FiZXI6c2FiZXJfc2VjcmV0");
        headers.add("Blade-Auth", "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF2YXRhciI6Imh0dHBzOi8vZ3cuYWxpcGF5b2JqZWN0cy5jb20vem9zL3Jtc3BvcnRhbC9CaWF6ZmFueG1hbU5Sb3h4VnhrYS5wbmciLCJhdXRob3JpdGllcyI6WyJhZG1pbmlzdHJhdG9yIl0sImNsaWVudF9pZCI6InNhYmVyIiwicm9sZV9uYW1lIjoiYWRtaW5pc3RyYXRvciIsImxpY2Vuc2UiOiJwb3dlcmVkIGJ5IGJsYWRleCIsInVzZXJfaWQiOiIxMTIzNTk4ODIxNzM4Njc1MjAxIiwicm9sZV9pZCI6IjExMjM1OTg4MTY3Mzg2NzUyMDEiLCJzY29wZSI6WyJhbGwiXSwibmlja19uYW1lIjoi566h55CG5ZGYIiwiZXhwIjoxNTg5NzkyMzU5LCJkZXB0X2lkIjoiMTEyMzU5ODgxMzczODY3NTIwMSIsImp0aSI6IjQxNTNhYWE0LTJiM2ItNDQzMi1iZDRkLWY3NWQzZWU5ZDM0MiIsImFjY291bnQiOiJhZG1pbiJ9.h7sqj_0f4BKCFKO5rdtWY5d5jovZq88_Y_bk8rk7zAA");
        System.out.println(requestGet(restTemplate, "http://localhost/blade-user/detail", param, reference, headers));
    }
*/

}
